package es.xpt.ysf.commons.location;

import static javax.ejb.TransactionAttributeType.REQUIRED;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import es.xpt.ysf.YSFException;
import es.xpt.ysf.commons.location.dao.AddressDAO;
import es.xpt.ysf.commons.location.dao.CityDAO;
import es.xpt.ysf.commons.location.dao.CountryDAO;
import es.xpt.ysf.commons.location.dao.LocationDAOFactory;
import es.xpt.ysf.commons.location.dao.ProvinceDAO;
import es.xpt.ysf.commons.location.model.Address;
import es.xpt.ysf.commons.location.model.City;
import es.xpt.ysf.commons.location.model.Country;
import es.xpt.ysf.commons.location.model.CountryTags;
import es.xpt.ysf.commons.location.model.Province;
import es.xpt.ysf.configuration.Configuration;
import es.xpt.ysf.configuration.ConfigurationParameterNames;
import es.xpt.ysf.dao.DAOException;
import es.xpt.ysf.jaas.YSFPrincipal;
import es.xpt.ysf.logging.LogManager;
import es.xpt.ysf.model.TagMap;
import es.xpt.ysf.utils.UUID;

@Stateless(name = "LocationSession")
@TransactionAttribute(REQUIRED)
public class LocationSessionBean implements LocationSession { // NO_UCD


	@Resource
	private SessionContext context;
	
	@EJB LocationSession ls;

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#createCountry(es.xpt.ysf.commons.location.model.Country)
	 */
	public void createCountry(Country country) throws YSFException {

		if (!country.validateData())
			throw new YSFException(
					"commons.location.countryCreateErrorNotValidData");
		if (!country.checkRequired())
			throw new YSFException(
					"commons.location.countryCreateErrorCheckRequired");

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			CountryDAO dao = f.getCountryDAO();
			dao.insert(country);
		} finally {
			if (f != null)
				f.release();
		}
	}


	public void updateCountryi18n(List<Country> countryi18n)
			throws YSFException {
		for (Country country : countryi18n) {
			if (!country.checkPrimaryKey())
				throw new YSFException(
						"commons.location.countryModifyErrorCheckRequired");
		}
		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			CountryDAO dao = f.getCountryDAO();
			for (Country country : countryi18n) {
				dao.update(country);
			}
		} finally {
			if (f != null)
				f.release();
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#deleteCountry(java.lang.String,
	 *      java.lang.String)
	 */
	public void deleteCountry(String id, String locale) throws YSFException {

		if (id == null)
			throw new YSFException(
					"commons.location.countryDeleteErrorCheckRequired");

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			CountryDAO dao = f.getCountryDAO();
			dao.delete(id, locale);
		} catch (DAOException e) {
			throw e;
		} finally {
			if (f != null)
				f.release();
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#getCountry(java.lang.String)
	 */
	public List<Country> getCountry(String id) throws YSFException {
		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			CountryDAO dao = f.getCountryDAO();
			return dao.getCountry(id);
		} finally {
			if (f != null)
				f.release();
		}
	}

	
	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#findAllCountry()
	 */
	public List<Country> findAllCountry() throws YSFException {

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			CountryDAO dao = f.getCountryDAO();
			return dao.findAll(null);
		} finally {
			if (f != null)
				f.release();
		}

	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#getCountries()
	 */
	public List<Country> getCountries() throws YSFException {

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			CountryDAO dao = f.getCountryDAO();
			TagMap t = new TagMap(1);
			t.put(CountryTags.SHOW);
			return dao.findAll(t);
		} finally {
			if (f != null)
				f.release();
		}

	}

	public List<Country> suggestCountries(String fragment) throws YSFException {
		List<Country> result = null;
		if (fragment != null) {
			LocationDAOFactory f = null;
			try {
				f = new LocationDAOFactory(context.getCallerPrincipal());
				CountryDAO dao = f.getCountryDAO();
				result = dao.suggestCountries(fragment);
			} catch (DAOException e) {
			 	LogManager.getLog(this.getClass()).error(e.getMessage() + " :fragment: " + fragment);
			} finally {
				if (f != null)
					f.release();
			}
		}
		return result;
	}
	
	/* ************************************PROVINCIAS************************************************** */

	
	public void updateProvinceI18n(List<Province> provincei18n)
			throws YSFException {
		for (Province province : provincei18n) {
			if (!province.checkPrimaryKey())
				throw new YSFException(
						"commons.location.countryModifyErrorCheckRequired");
		}
		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			ProvinceDAO dao = f.getProvinceDAO();
			for (Province province : provincei18n) {
				dao.update(province);
			}
		} finally {
			if (f != null)
				f.release();
		}

	}
	
	/**
	 * This method return a List containing all external province
	 * 
	 * @return List with the matching objects.
	 * @exception YSFException
	 */
	public List<Province> getAllProvinceByCountry(String country) throws YSFException 
	{
		if (country == null || country.trim().length() == 0)
			return new ArrayList<Province>(0);

		LocationDAOFactory f = null;
		try 
		{
			f = new LocationDAOFactory(context.getCallerPrincipal(), getContainerJndiName());
			return f.getProvinceDAO().findAllProvincesByCountry(country);
		} 
		finally 
		{
			if (f != null)
				f.release();
		}

	}
	
	private String getContainerJndiName () {
		String jndiName = new Configuration((YSFPrincipal)context.getCallerPrincipal()).getString(ConfigurationParameterNames.LOCATIONS_CONTAINER_JNDI);
		if(jndiName==null || jndiName.isEmpty() )
			return ((YSFPrincipal)context.getCallerPrincipal()).getDatasource();
		return jndiName;
	}

	/**
	 * This method return a List containing all countries
	 * 
	 * @return List with the matching objects.
	 * @exception YSFException
	 */
	public List<Province> getProvinceByCountry(String country)
			throws YSFException {

		if (country == null || country.trim().length() == 0)
			return new ArrayList<Province>(0);

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			return f.getProvinceDAO().findByCountry(country, false);
		} finally {
			if (f != null)
				f.release();
		}

	}

	public List<Province> getUsedProvincesByCountry(String country) throws YSFException {

		if (country == null || country.trim().length() == 0)
			return new ArrayList<Province>(0);
		
		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			return f.getProvinceDAO().findByCountry(country, true);
		} finally {
			if (f != null)
				f.release();
		}

	}

	
	public List<Province> getProvince(String id) throws YSFException {

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			ProvinceDAO dao = f.getProvinceDAO();
			return dao.getProvince(id);
		} finally {
			if (f != null)
				f.release();
		}

	}
	
	public Province getProvince(String id, String locale) throws YSFException {
		if (id == null)
			throw new NullPointerException("id");
		
		if (locale == null)
			throw new NullPointerException("locale");
		
		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			ProvinceDAO dao = f.getProvinceDAO();
			return dao.getProvince(id,locale);
		} finally {
			if (f != null)
				f.release();
		}

	}

	/**
	 * Create method will call insert DAO object method. Make sure that values
	 * for all requiered properties are correctly specified.
	 * 
	 * @param province
	 *            This parameter contains the class instance to be created.
	 * 
	 * @exception YSFException
	 */
	public void createProvince(Province newProvince) throws YSFException {

		if (newProvince == null)
			throw new NullPointerException("newProvince");

		boolean onlyNewDescription = true;

		if (newProvince.getCode() == null) {
			// Nueva provincia
			newProvince.setCode(UUID.randomUUID());
			newProvince.setLocale(((YSFPrincipal) context.getCallerPrincipal())
					.getLocale().toString());
			onlyNewDescription = false;
			if (!newProvince.checkRequired())
				throw new YSFException(
						"commons.location.provinceCreateErrorCheckRequired");
			if (!newProvince.validateData())
				throw new YSFException(
						"commons.location.provinceCreateErrorNotValidData");
		} else {
			if (!newProvince.checkRequiredI18n())
				throw new YSFException(
						"commons.location.provinceCreateErrorCheckRequired");
			if (!newProvince.validateData())
				throw new YSFException(
						"commons.location.provinceCreateErrorNotValidData");
		}

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			ProvinceDAO dao = f.getProvinceDAO();
			if (!onlyNewDescription)
				dao.insertProvince(newProvince);

			// Metemos el nombre en el idioma que tenga cargado
			dao.insertProvincei18n(newProvince);

		} catch (DAOException e) {
			newProvince.setCode(null);
			context.setRollbackOnly();
			throw e;
		} finally {
			if (f != null)
				f.release();
		}
	}

	public void deleteProvince(Province province, String locale)
			throws YSFException {
		if (province == null)
			throw new YSFException(
					"commons.location.provinceDeleteErrorCheckRequired");
		String id = province.getCode();
		if (id == null)
			throw new YSFException(
					"commons.location.provinceDeleteErrorCheckRequired");
		LocationDAOFactory f = new LocationDAOFactory(context
				.getCallerPrincipal());

		ProvinceDAO dao = null;
		CityDAO cityDao = null;

		try {
			cityDao = f.getCityDAO();
			cityDao.deleteCitiesInProvince(province.getCode());
			dao = f.getProvinceDAO();
			if (locale == null) {
				City settlement = new City();
				settlement.setProvinceCode(id);
				dao.delete(id);
			} else {
				dao.deletei18n(id, locale);
			}

		} catch (DAOException e) {
			context.setRollbackOnly();
			throw e;
		} finally {
			if (f != null)
				f.release();
		}
		
	}
	
	public List<Province> suggestProvinces(String fragment) throws YSFException {
		List<Province> result = null;
		if (fragment != null) {
			LocationDAOFactory f = null;
			try {
				f = new LocationDAOFactory(context.getCallerPrincipal());
				ProvinceDAO dao = f.getProvinceDAO();
				result = dao.suggestProvinces(fragment);
			} catch (DAOException e) {
			 	LogManager.getLog(this.getClass()).error(e.getMessage() + " :fragment: " + fragment);
			} finally {
				if (f != null)
					f.release();
			}
		}
		return result;
	}
	
	/* ************************************Ciudades************************************************** */

	public void updateCityI18n(List<City> cityi18n)
			throws YSFException {
		for (City city : cityi18n) {
			if (!city.checkPrimaryKey())
				throw new YSFException(
						"commons.location.provinceModifyErrorCheckRequired");
		}
		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			CityDAO dao = f.getCityDAO();
			for (City city : cityi18n) {
				dao.update(city);
			}
		} finally {
			if (f != null)
				f.release();
		}

	}
	
	/**
	 * This method return a List containing all external cities
	 * 
	 * @return List with the matching objects.
	 * @exception YSFException
	 */	
	public List<City> getAllCityByProvince(String province) throws YSFException 
	{
		if (province == null || province.trim().length() == 0)
			return new ArrayList<City>(0);

		LocationDAOFactory f = null;
		try 
		{
			f = new LocationDAOFactory(context.getCallerPrincipal(), getContainerJndiName());
			return f.getCityDAO().findAllCitiesByProvince(province);
		} 
		finally 
		{
			if (f != null)
				f.release();
		}
	}

	/**
	 * This method return a List containing all countries
	 * 
	 * @return List with the matching objects.
	 * @exception YSFException
	 */
	public List<City> getCityByProvince(String province)
			throws YSFException {

		if (province == null || province.trim().length() == 0)
			return new ArrayList<City>(0);

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			return f.getCityDAO().findByProvince(province, false);
		} finally {
			if (f != null)
				f.release();
		}

	}
	
	public List<City> getUsedCitiesByProvince(String province) throws YSFException {

		if (province == null || province.trim().length() == 0)
			return new ArrayList<City>(0);

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			return f.getCityDAO().findByProvince(province, true);
		} finally {
			if (f != null)
				f.release();
		}
	}


	public List<City> getCity(String id) throws YSFException {

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			CityDAO dao = f.getCityDAO();
			return dao.getCity(id);
		} finally {
			if (f != null)
				f.release();
		}
	}
	
	public City getCityLanguage(String id) throws YSFException {

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			CityDAO dao = f.getCityDAO();
			return dao.getCityLanguage(id);
		} finally {
			if (f != null)
				f.release();
		}
	}
	
	public void createCity(City newCity) throws YSFException {

		if (newCity == null)
			throw new NullPointerException("newCity");

		boolean onlyNewDescription = true;

		if (newCity.getCode() == null) {
			// Nueva provincia
			newCity.setCode(UUID.randomUUID());
			newCity.setLocale(((YSFPrincipal) context.getCallerPrincipal())
					.getLocale().toString());
			onlyNewDescription = false;
			if (!newCity.checkRequired())
				throw new YSFException(
						"commons.location.cityCreateErrorCheckRequired");
			if (!newCity.validateData())
				throw new YSFException(
						"commons.location.cityCreateErrorNotValidData");
		} else {
			if (!newCity.checkRequiredI18n())
				throw new YSFException(
						"commons.location.cityCreateErrorCheckRequired");
			if (!newCity.validateData())
				throw new YSFException(
						"commons.location.cityCreateErrorNotValidData");
		}

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			CityDAO dao = f.getCityDAO();
			if (!onlyNewDescription)
				dao.insertCity(newCity);

			// Metemos el nombre en el idioma que tenga cargado
			dao.insertCityi18n(newCity);

		} catch (DAOException e) {
			newCity.setCode(null);
			context.setRollbackOnly();
			throw e;
		} finally {
			if (f != null)
				f.release();
		}
	}

	/**
	 * This method will remove the information identified by by primary-key in
	 * supplied city. If delete can not find an existing instance,
	 * YSFException will be thrown.
	 * 
	 * @param city
	 *            This parameter contains the class instance to be deleted.
	 *            Primary-key field must be set for this to work properly.
	 * @exception YSFException
	 */
	public void deleteCity(String id, String locale) throws YSFException {

		if (id == null)
			throw new YSFException(
					"commons.location.cityDeleteErrorCheckRequired");
		LocationDAOFactory f = new LocationDAOFactory(context
				.getCallerPrincipal());

		CityDAO dao = null;
		try {
			dao = f.getCityDAO();
			if (locale == null) {
				dao.delete(id);
			} else {
				dao.deletei18n(id, locale);
			}

		} catch (DAOException e) {
			context.setRollbackOnly();
			throw e;
		} finally {
			if (f != null)
				f.release();
		}
	}
	

	
	/**
	 * *********************** DIRECCIONES
	 * ***********************************************
	 */

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#getEntityAddresses(java.lang.String,
	 *      java.lang.String)
	 */
	public List<Address> getEntityAddresses(String entity, String entityId)
			throws YSFException {
		if (entity == null || entity.trim().length() <= 0)
			throw new NullPointerException("entity");

		if (entityId == null || entityId.trim().length() <= 0)
			throw new NullPointerException("entityId");

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			AddressDAO dao = f.getAddressDAO();
			return dao.getEntityAddresses(entityId, entity);
		} finally {
			if (f != null)
				f.release();
		}
	}
	
	public Address getEntityAddressByUse(String entity, String entityId,
			String use) throws YSFException {
		if (entity == null || entity.trim().length() <= 0)
			throw new NullPointerException("entity");

		if (entityId == null || entityId.trim().length() <= 0)
			throw new NullPointerException("entityId");
		
		if (use == null || use.trim().length() <= 0)
			throw new NullPointerException("use");

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			AddressDAO dao = f.getAddressDAO();
			return dao.getEntityAddressByUse(entityId, entity, use);
		} finally {
			if (f != null)
				f.release();
		}	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#addEntityAddress(java.lang.String,
	 *      java.lang.String, java.lang.String, java.lang.String)
	 */
	public void addEntityAddress(String entityId, String entity,
			String addressId, String use) throws YSFException {
		if (entity == null || entity.trim().length() <= 0)
			throw new NullPointerException("entity");

		if (entityId == null || entityId.trim().length() <= 0)
			throw new NullPointerException("entityId");

		if (addressId == null || addressId.trim().length() <= 0)
			throw new NullPointerException("addressId");

		if (use == null || use.trim().length() <= 0)
			throw new NullPointerException("use");

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			AddressDAO dao = f.getAddressDAO();
			dao.addEntityAddress(entityId, entity, addressId, use);
			if ( entity.equals("tio_product") && use.equals("200")) {
				Address a = dao.getAddress(addressId);
				dao.updateProductCity(entityId, a.getCity().getCode());
			}
			
		} finally {
			if (f != null)
				f.release();
		}
	}
	
	/* (non-Javadoc)
	 * @see es.xpt.ysf.commons.location.LocationSession#addEntityAddress(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
	 */
	public void addEntityAddresses(String entityId, String entity,
			List<String> addresses, String use) throws YSFException {
		if (entity == null || entity.trim().length() <= 0)
			throw new NullPointerException("entity");

		if (entityId == null || entityId.trim().length() <= 0)
			throw new NullPointerException("entityId");

		if (addresses == null || addresses.size() <= 0)
			throw new NullPointerException("addresses");

		if (use == null || use.trim().length() <= 0)
			throw new NullPointerException("use");

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			AddressDAO dao = f.getAddressDAO();
			dao.addBatchEntityAddress(entityId, entity, addresses, use);
		} finally {
			if (f != null)
				f.release();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#removeEntityAddress(java.lang.String,
	 *      java.lang.String, java.lang.String, java.lang.String)
	 */
	public void removeEntityAddress(String entityId, String entity,
			String addressId, String use) throws YSFException {
		if (entity == null || entity.trim().length() <= 0)
			throw new NullPointerException("entity");

		if (entityId == null || entityId.trim().length() <= 0)
			throw new NullPointerException("entityId");

		if (addressId == null || addressId.trim().length() <= 0)
			throw new NullPointerException("addressId");

		if (use == null || use.trim().length() <= 0)
			throw new NullPointerException("use");

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			AddressDAO dao = f.getAddressDAO();
			dao.removeEntityAddress(entityId, entity, addressId, use);
			if ( entity.equals("tio_product") && use.equals("200") ) {
				dao.updateProductCity(entityId, null);
			}
		} finally {
			if (f != null)
				f.release();
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#searchAddress(es.xpt.ysf.commons.location.model.Address)
	 */
	public List<Address> searchAddress(Address address) throws YSFException {
		if (address == null)
			throw new NullPointerException("address");

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			AddressDAO dao = f.getAddressDAO();
			return dao.searchAddress(address);
		} finally {
			if (f != null)
				f.release();
		}

	}
	
	/* (non-Javadoc)
	 * @see es.xpt.ysf.commons.location.LocationSession#searchCity(es.xpt.ysf.commons.location.model.City)
	 */
	public List<City> searchCity(City city) throws YSFException {
		if (city == null)
			throw new NullPointerException("city");

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			CityDAO dao = f.getCityDAO();
			return dao.searchCity(city);
		} finally {
			if (f != null)
				f.release();
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#searchDependentEntities(es.xpt.ysf.commons.location.model.Address)
	 */
	public ArrayList<String[]> searchDependentEntities(String addressId)
			throws YSFException {
		if (addressId == null)
			throw new NullPointerException("addressId");

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			AddressDAO dao = f.getAddressDAO();
			return dao.searchDependentEntities(addressId);
		} finally {
			if (f != null)
				f.release();
		}

	}

	
	private Cache getCache() {
		return CacheManager.getInstance().getCache("addresses@" + ((YSFPrincipal) context.getCallerPrincipal()).getApplication());
	}
	
	private void removeFromCache(String id) {
		Cache cache = getCache();
		if (cache != null) {
			getCache().remove(id);
		}
	}
	
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#insertProvinceCityFromAddress(es.xpt.ysf.commons.location.dao.LocationDAOFactory,es.xpt.ysf.commons.location.model.Address)
	 */
	private void insertProvinceCityFromAddress(LocationDAOFactory f, Address address)
	{
		try
		{
			// insert province
			ProvinceDAO provinceDAO = f.getProvinceDAO();
			provinceDAO.insertProvince(address.getProvince());
			provinceDAO.insertProvincei18n(address.getProvince());
			// insert city
			CityDAO cityDAO = f.getCityDAO();
			cityDAO.insertCity(address.getCity());
			cityDAO.insertCityi18n(address.getCity());
		}
		catch(Exception e)
		{
			LogManager.getLog(this.getClass()).debug(e.getMessage());
		}
	}

	
	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#searchEntityDependences(es.xpt.ysf.commons.location.model.Address)
	 */
	public List<String> searchEntityDependences(String addressId, String entity)
			throws YSFException {
		if (addressId == null || addressId.trim().length() <= 0)
			throw new NullPointerException("addressId");

		if (entity == null || entity.trim().length() <= 0)
			throw new NullPointerException("entity");

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			AddressDAO dao = f.getAddressDAO();
			return dao.searchEntityDependences(addressId, entity, null);
		} finally {
			if (f != null)
				f.release();
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#getAddress(java.lang.String)
	 */
	public Address getAddress(String id) throws YSFException {

		if (id == null || id.trim().length() <= 0)
			throw new NullPointerException("id");
		
		Address result = null;
		Cache cache = getCache();
		if (cache != null) {
			Element element = cache.get(id);
			if (element != null && element.getObjectValue() != null && element.getObjectValue() instanceof Address) {
				result = (Address) element.getObjectValue();
				if (result != null)
					result = (Address) result.clone();
			}
		}

		if (result == null) {
			LocationDAOFactory f = null;
			try {
				f = new LocationDAOFactory(context.getCallerPrincipal());
				AddressDAO dao = f.getAddressDAO();
				result = dao.getAddress(id);
				if (result != null && cache != null) {
					Element element = new Element(id, result.clone());
					cache.put(element);
				}
			} finally {
				if (f != null)
					f.release();
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#updateAddress(es.xpt.ysf.commons.location.model.Address)
	 */
	public void updateAddress(Address address) throws YSFException {
		if (address == null)
			throw new NullPointerException("address");

		address.check();

		removeFromCache(address.getId());
		
		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			insertProvinceCityFromAddress(f,address);
			AddressDAO dao = f.getAddressDAO();
			dao.update(address);
			List<String> productIds = dao.searchEntityDependences(address.getId(), "tio_product", "200");
			for ( String productId: productIds ) {
				dao.updateProductCity(productId, address.getCity().getCode());
			}
		} finally {
			if (f != null)
				f.release();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#insertAddress(es.xpt.ysf.commons.location.model.Address)
	 */
	public Address insertAddress(Address address) throws YSFException {
		if (address == null)
			throw new NullPointerException("address");

		address.setId(UUID.randomUUID());
		address.check();

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			insertProvinceCityFromAddress(f,address);
			AddressDAO dao = f.getAddressDAO();
			dao.insert(address);
			return address;		
		} finally {
			if (f != null)
				f.release();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#insertAddress(es.xpt.ysf.commons.location.model.Address,
	 *      java.lang.String, java.lang.String)
	 */
	public Address insertAddress(Address address, String entity, String entityId)
			throws YSFException {
		if (address == null)
			throw new NullPointerException("address");

		if (entity == null || entity.trim().length() <= 0)
			throw new NullPointerException("entity");

		if (entityId == null || entityId.trim().length() <= 0)
			throw new NullPointerException("entityId");

		if (address.getUseType() == null
				|| address.getUseType().getCode() == null
				|| address.getUseType().getCode().length() <= 0)
			throw new NullPointerException("address.useType");

		address.setId(UUID.randomUUID());
		address.check();

		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			insertProvinceCityFromAddress(f,address);
			AddressDAO dao = f.getAddressDAO();
			dao.insert(address);
			dao.addEntityAddress(entityId, entity, address.getId(), address.getUseType().getCode());
			
			if ( entity.equals("tio_product") && address.getUseType().getCode().equals("200") ) {
				dao.updateProductCity(entityId, address.getCity().getCode());
			}
			
			return address;
		} finally {
			if (f != null)
				f.release();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see es.xpt.ysf.commons.location.LocationSession#deleteAddress(java.lang.String)
	 */
	public void deleteAddress(String id) throws YSFException {
		if (id == null || id.trim().length() <= 0)
			throw new NullPointerException("id");

		removeFromCache(id);

		
		LocationDAOFactory f = null;
		try {
			f = new LocationDAOFactory(context.getCallerPrincipal());
			AddressDAO dao = f.getAddressDAO();
			dao.delete(id);
		} finally {
			if (f != null)
				f.release();
		}

	}

	public List<String> deleteBatchAddress(List<String> listCodeAddress) throws YSFException{
		if (listCodeAddress==null)
			throw new NullPointerException("listCodeAddress");
		
			if (listCodeAddress.size()>0){
				List<String> listMessages = new ArrayList<String>();
				try{
					 ls.deleteBatchAddressNewTransactional(listCodeAddress);
				}catch (DAOException e){
					for ( String code: listCodeAddress) {
						try {
							ls.deleteAddressNewTransactional(code);
						}catch (DAOException daoe) {
							listMessages.add(daoe.getMessage());
							listMessages.add((daoe.getParameters()!=null) ? (String)daoe.getParameters()[0]: "");
						}
					}
				}
				return listMessages;
		}else
			return null;
	}

	@TransactionAttribute (TransactionAttributeType.REQUIRES_NEW)
	public void deleteBatchAddressNewTransactional(List<String> listAddress) throws YSFException{
		if ( listAddress==null)
			throw new NullPointerException(" listAddress");
		
		
		
		if( listAddress.size()>0){
			
			for (String currentId : listAddress) {
				removeFromCache(currentId);
			}
			
			LocationDAOFactory r = null;
			
			try {
				r = new LocationDAOFactory(context.getCallerPrincipal());
				AddressDAO dao = r.getAddressDAO();		 					 
				dao.deleteBatchAddress(listAddress);	
			} catch (DAOException e) {
				context.setRollbackOnly();
				throw e;
			} finally {
				if (r != null) r.release();
			} 
		}
	}
	@TransactionAttribute (TransactionAttributeType.REQUIRES_NEW)
	public void deleteAddressNewTransactional(String codeAddress) throws YSFException{
		if (codeAddress==null)
			throw new NullPointerException("codeAddress");

		removeFromCache(codeAddress);

			LocationDAOFactory r = null;
		
		try {
			r = new LocationDAOFactory(context.getCallerPrincipal());
			AddressDAO dao = r.getAddressDAO();		 					 
			dao.delete(codeAddress);
		} catch (DAOException e) {
			context.setRollbackOnly();
		 	String[] params = new String[1];
		 	params[0]= codeAddress;
		 	LogManager.getLog(this.getClass()).debug(e.getMessage()+" :id: "+codeAddress);
			throw new DAOException(e.getMessage(),params);
		} finally {	
			if (r != null) r.release();
		} 
	}

	public List<City> suggestCities(String fragment) throws YSFException {
		List<City> result = null;
		if (fragment != null) {
			LocationDAOFactory f = null;
			try {
				f = new LocationDAOFactory(context.getCallerPrincipal());
				CityDAO dao = f.getCityDAO();
				result = dao.suggestCities(fragment);
			} finally {
				if (f != null)
					f.release();
			}
		}
		return result;
	}
	public List<City> suggestMainCitiesForEntity(String fragment, int maxResults, String entity) throws YSFException {
		List<City> result = null;
		if (fragment != null) {
			LocationDAOFactory f = null;
			try {
				f = new LocationDAOFactory(context.getCallerPrincipal());
				CityDAO dao = f.getCityDAO();
				result = dao.suggestMainCitiesForEntity(fragment, maxResults, entity);
			} catch (DAOException e) {
			 	LogManager.getLog(this.getClass()).error(e.getMessage() + " :fragment: " + fragment);
			} finally {
				if (f != null)
					f.release();
			}
		}
		return result;
	}
}
